/*
 * Copyright (C) 2010  Paulo Cesar Pereira de Andrade.
 *
 * This is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * Authors:
 *	Paulo Cesar Pereira de Andrade
 */

#if PROTO
static east_list_t *parse_int(east_list_t *list, east_node_t *node);
static east_list_t *emit_int(east_list_t *list, east_node_t *node);

static east_list_t *parse_long(east_list_t *list, east_node_t *node);
static east_list_t *emit_long(east_list_t *list, east_node_t *node);

static east_list_t *parse_float(east_list_t *list, east_node_t *node);
static east_list_t *emit_float(east_list_t *list, east_node_t *node);

static east_list_t *parse_ldt(east_list_t *list, east_node_t *node);
static east_list_t *emit_ldt(east_list_t *list, east_node_t *node);

static east_list_t *parse_lb(east_list_t *list, east_node_t *node);
static east_list_t *emit_lb(east_list_t *list, east_node_t *node);

static east_list_t *parse_lbt(east_list_t *list, east_node_t *node);
static east_list_t *emit_lbt(east_list_t *list, east_node_t *node);

static east_list_t *parse_lr(east_list_t *list, east_node_t *node);
static east_list_t *emit_lr(east_list_t *list, east_node_t *node);

static east_list_t *parse_lc(east_list_t *list, east_node_t *node);
static east_list_t *emit_lc(east_list_t *list, east_node_t *node);

static east_list_t *parse_sdt(east_list_t *list, east_node_t *node);
static east_list_t *emit_sdt(east_list_t *list, east_node_t *node);

static east_list_t *parse_sb(east_list_t *list, east_node_t *node);
static east_list_t *emit_sb(east_list_t *list, east_node_t *node);

static east_list_t *parse_sbt(east_list_t *list, east_node_t *node);
static east_list_t *emit_sbt(east_list_t *list, east_node_t *node);

static east_list_t *
parse_ss(east_list_t *list, east_node_t *node, eobject_t function);
static east_list_t *emit_ss(east_list_t *list, east_node_t *node);
static east_list_t *emit_ssv(east_list_t *list, east_node_t *node);

static east_list_t *parse_sst(east_list_t *list, east_node_t *node);
static east_list_t *emit_sst(east_list_t *list, east_node_t *node);

static east_list_t *parse_sc(east_list_t *list, east_node_t *node);
static east_list_t *emit_sc(east_list_t *list, east_node_t *node);

static east_list_t *
parse_push(east_list_t *list, east_node_t *node, eobject_t function);
static east_list_t *emit_push(east_list_t *list, east_node_t *node);
static east_list_t *emit_pushv(east_list_t *list, east_node_t *node);

static east_list_t *parse_pusht(east_list_t *list, east_node_t *node);
static east_list_t *emit_pusht(east_list_t *list, east_node_t *node);

static void parse_inc_int32(void);
static void parse_inc_int(void);
static void parse_inc_uint(void);
static void parse_inc_mpz(void);
static void parse_inc_float(void);
static east_list_t *parse_inc(east_list_t *list, east_node_t *node);
static east_list_t *emit_inc(east_list_t *list, east_node_t *node);

static void parse_dec_int32(void);
static void parse_dec_int(void);
static void parse_dec_uint(void);
static void parse_dec_mpz(void);
static void parse_dec_float(void);
static east_list_t *parse_dec(east_list_t *list, east_node_t *node);
static east_list_t *emit_dec(east_list_t *list, east_node_t *node);

static void cmp_int32_int32(eint32_t code, ecode_t opcode);
static void cmp_int32_float(eint32_t code, eint32_t opcode);
static void cmp_int_int(eint32_t code, eint32_t opcode);
static void
cmp_any_int(eint32_t code, ecode_t opcode, elit_node_t *fail);
#if __WORDSIZE == 64
static void cmp_int_float(eint32_t code, ecode_t opcode);
#endif
static void cmp_inner_float_float(eint32_t code, ecode_t opcode);
static void cmp_float_float(eint32_t code, ecode_t opcode);
static void cmp_any_float32(eint32_t code, ecode_t opcode, elit_node_t *fail);
static void cmp_any_float(eint32_t code, ecode_t opcode, elit_node_t *fail);
static void cmp_any_any(eint32_t code, eint32_t opcode);
static east_list_t *parse_cmp(east_list_t *list, east_node_t *node);
static east_list_t *emit_cmp(east_list_t *list, east_node_t *node);

static void as_l_i_i(eint32_t code, ecode_t opcode);
static void as_l_l_l(eint32_t code, ecode_t opcode);
static void
as_a_l_l(eint32_t code, ecode_t opcode,
	 ebool_t sync, ebool_t type, elit_node_t *fail);
static void as_a_l_a(eint32_t code, ecode_t opcode, elit_node_t *fail);
static void as_a_a_l(eint32_t code, ecode_t opcode, elit_node_t *fail);
static void as_inner_d_d_d(eint32_t code, ecode_t opcode);
static void as_d_i_d(eint32_t code, ecode_t opcode);
#if __WORDSIZE == 64
static void as_d_l_d(eint32_t code, ecode_t opcode);
#endif
static void as_d_d_d(eint32_t code, ecode_t opcode);
static void as_a_d_a(eint32_t code, ecode_t opcode, elit_node_t *fail);
static void as_a_a_d(eint32_t code, ecode_t opcode, elit_node_t *fail);
static void as_a_a_a(eint32_t code, ecode_t opcode);
static east_list_t *parse_addsub(east_list_t *list, east_node_t *node);
static east_list_t *emit_addsub(east_list_t *list, east_node_t *node);
#endif

#if CODE
#define load_stack(code)						\
    new_ldxi_p(code, JIT_R1, JIT_V0, offsetof(ethread_t, esp))
#define pop_stack(code)							\
    new_subi_p(code, JIT_R1, JIT_R1, sizeof(evalue_t));			\
    new_stxi_p(code, offsetof(ethread_t, esp), JIT_V0, JIT_R1)
static east_list_t *
parse_int(east_list_t *list, east_node_t *node)
{
    edata_t		data;
    data.L = immediate_int(node);
    new_movi_i(icode, JIT_V1, data.s.l);
    lit_sync = lit_sync_register;
    lit_type = t_int32;
    return (list);
}
static east_list_t *
emit_int(east_list_t *list, east_node_t *node)
{
    list = parse_int(list, node);
    parse_flush(0);
    return (list);
}

static east_list_t *
parse_long(east_list_t *list, east_node_t *node)
{
    edata_t		data;
    data.L = immediate_int(node);
#if __WORDSIZE == 32
    new_movi_i(icode, JIT_V1, data.s.l);
    new_movi_i(icode, JIT_V2, data.s.h);
#else
    new_movi_l(icode, JIT_V1, data.L);
#endif
    lit_sync = lit_sync_register;
    lit_type = t_int;
    return (list);
}
static east_list_t *
emit_long(east_list_t *list, east_node_t *node)
{
    list = parse_long(list, node);
    parse_flush(0);
    return (list);
}

static east_list_t *
parse_float(east_list_t *list, east_node_t *node)
{
    edata_t		data;
    data.F = immediate_float(node);
    new_movi_d(fcode, JIT_FPR0, data.F);
    lit_sync = lit_sync_register;
    lit_type = t_float;
    return (list);
}
static east_list_t *
emit_float(east_list_t *list, east_node_t *node)
{
    list = parse_float(list, node);
    parse_flush(0);
    return (list);
}

static east_list_t *
parse_ldt(east_list_t *list, east_node_t *node)
{
#define load_pointer(code)		new_ldi_p(code, JIT_R1, base)
    eobject_t		base;
    base = (eint8_t *)eds + node->csymbol.symbol->offset * sizeof(eobject_t);
    switch (lit_type = node->csymbol.symbol->type) {
	case t_int8:			case t_uint8:
	case t_int16:			case t_uint16:
	case t_int32:			case t_uint32:
	case t_int:			case t_uint:
	    load_pointer(icode);
	    load_ireg_type(icode, 0);
	    break;
	case t_float32:			case t_float:
	    load_pointer(fcode);
	    load_freg_type(fcode, 0);
	    break;
	default:
	    abort();
    }
    lit_sync = lit_sync_register;
    return (list);
#undef load_pointer
}
static east_list_t *
emit_ldt(east_list_t *list, east_node_t *node)
{
    list = parse_ldt(list, node);
    parse_flush(0);
    return (list);
}

static east_list_t *
parse_lb(east_list_t *list, east_node_t *node)
{
    elit_node_t		*next;
    elit_node_t		*idone;
    elit_node_t		*fdone;
    eint32_t		 offset;
    offset = node->csymbol.symbol->offset * sizeof(evalue_t);
    new_ldxi_p(icode, JIT_R1, JIT_V0, offsetof(ethread_t, ebp));
    new_ldxi_i(icode, JIT_R0, JIT_R1, offset + offsetof(evalue_t, t));
    next = new_bnei_i(icode, null, JIT_R0, t_int);
    load_ireg(icode, JIT_R1, offset + offsetof(evalue_t, v.i));
    store_ireg_implicit(icode, true);
    idone = new_jmpi(icode, null);
    new_label(fcode, next);
    next = new_bnei_i(fcode, null, JIT_R0, t_float);
    load_freg(fcode, JIT_R1, offset + offsetof(evalue_t, v.d));
    store_freg_implicit(fcode, true);
    fdone = new_jmpi(fcode, null);
    new_label(acode, next);
    call_i(acode, evm_lb, node->csymbol.symbol->offset);
    new_label(acode, idone);
    new_label(acode, fdone);
    lit_sync = lit_sync_register|lit_sync_implicit;
    lit_type = t_any;
    return (list);
}
static east_list_t *
emit_lb(east_list_t *list, east_node_t *node)
{
    list = parse_lb(list, node);
    parse_flush(0);
    return (list);
}

static east_list_t *
parse_lbt(east_list_t *list, east_node_t *node)
{
#define load_pointer(code)						\
    new_ldxi_p(code, JIT_R1, JIT_V0, offsetof(ethread_t, ebp))
    switch (lit_type = node->csymbol.symbol->type) {
	case t_int8:			case t_uint8:
	case t_int16:			case t_uint16:
	case t_int32:			case t_uint32:
	case t_int:			case t_uint:
	    load_pointer(icode);
	    load_ireg_type(icode, node->csymbol.symbol->offset *
			   sizeof(evalue_t) + offsetof(evalue_t, v.i));
	    break;
	case t_float32:			case t_float:
	    load_pointer(fcode);
	    load_freg_type(fcode, node->csymbol.symbol->offset *
			   sizeof(evalue_t) + offsetof(evalue_t, v.d));
	    break;
	default:
	    abort();
    }
    lit_sync = lit_sync_register;
    return (list);
#undef load_pointer
}
static east_list_t *
emit_lbt(east_list_t *list, east_node_t *node)
{
    list = parse_lbt(list, node);
    parse_flush(0);
    return (list);
}

static east_list_t *
parse_lr(east_list_t *list, east_node_t *node)
{
#define load_pointer(code)						\
    new_ldxi_i(code, JIT_R0, JIT_V0,					\
	       offsetof(ethread_t, r0) + offsetof(evalue_t, t));	\
    jump = new_beqi_i(code, null, JIT_R0, base);			\
    new_prepare(code, 3);						\
    new_movi_i(code, JIT_R1, offset);					\
    new_pusharg_i(code, JIT_R1);					\
    new_pusharg_i(code, JIT_R0);					\
    new_movi_i(code, JIT_R0, base);					\
    new_pusharg_i(code, JIT_R0);					\
    new_finish(code, evm_match_inheritance);				\
    new_label(code, jump);						\
    new_ldxi_p(code, JIT_R1, JIT_V0,					\
	       offsetof(ethread_t, r0) + offsetof(evalue_t, v.o))
    elit_node_t		*jump;
    eint32_t		 base;
    eint32_t		 type;
    eint32_t		 offset;
    esymbol_t		*symbol;
    symbol = node->crecord.symbol;
    base = node->crecord.record->type;
    offset = symbol->offset;
    type = symbol->type;
    emit_flush(0);
    switch (lit_type = type) {
	case t_int8:			case t_uint8:
	case t_int16:			case t_uint16:
	case t_int32:			case t_uint32:
	case t_int:			case t_uint:
	    load_pointer(icode);
	    load_ireg_type(icode, offset);
	    lit_sync = lit_sync_register;
	    break;
	case t_float32:			case t_float:
	    load_pointer(fcode);
	    load_freg_type(fcode, offset);
	    lit_sync = lit_sync_register;
	    break;
	default:
	    call_v_i_i_i(evm_lr, base, offset, type);
	    lit_sync = lit_sync_implicit;
	    lit_type = t_any;
	    break;
    }
    return (list);
#undef load_pointer
}
static east_list_t *
emit_lr(east_list_t *list, east_node_t *node)
{
    list = parse_lr(list, node);
    parse_flush(0);
    return (list);
}

static east_list_t *
parse_lc(east_list_t *list, east_node_t *node)
{
#define load_pointer(code)						\
    new_ldxi_p(code, JIT_R1, JIT_V0, offsetof(ethread_t, ebp));		\
    new_ldxi_p(code, JIT_R1, JIT_R1,					\
	       -2 * sizeof(evalue_t) + offsetof(evalue_t, v.o))
    esymbol_t		*symbol;
    symbol = node->csymbol.symbol;
    switch (lit_type = symbol->type) {
	case t_int8:			case t_uint8:
	case t_int16:			case t_uint16:
	case t_int32:			case t_uint32:
	case t_int:			case t_uint:
	    load_pointer(icode);
	    load_ireg_type(icode, symbol->offset);
	    lit_sync = lit_sync_register;
	    break;
	case t_float32:			case t_float:
	    load_pointer(fcode);
	    load_freg_type(fcode, symbol->offset);
	    lit_sync = lit_sync_register;
	    break;
	default:
	    emit_clear(0);
	    call_v_i_i(evm_lc, symbol->offset, symbol->type);
	    lit_sync = lit_sync_implicit;
	    lit_type = t_any;
	    break;
    }
    return (list);
#undef load_pointer
}
static east_list_t *
emit_lc(east_list_t *list, east_node_t *node)
{
    list = parse_lc(list, node);
    parse_flush(0);
    return (list);
}

static east_list_t *
parse_sdt(east_list_t *list, east_node_t *node)
{
#define load_pointer(code)		new_ldi_p(code, JIT_R1, base)
    eobject_t		 base;
    elit_node_t		*next;
    eint32_t		 sync;
    eint32_t		 type;
    type = node->csymbol.symbol->type;
    base = (eint8_t *)eds + node->csymbol.symbol->offset * sizeof(eobject_t);
    switch (lit_type) {
	case t_int8:			case t_uint8:
	case t_int16:			case t_uint16:
	case t_int32:			case t_uint32:
	    load_pointer(icode);
	    store_int32(icode, 0, type);
	    break;
	case t_int:			case t_uint:
	    load_pointer(icode);
	    store_int(icode, 0, type);
	    break;
	case t_float32:
	    load_pointer(fcode);
	    store_float32(fcode, 0, type);
	    break;
	case t_float:
	    load_pointer(fcode);
	    store_float(fcode, 0, type);
	    break;
	default:
	    new_ldxi_i(icode, JIT_R0, JIT_V0,
		       offsetof(ethread_t, r0) +  offsetof(evalue_t, t));
	    next = new_bnei_i(icode, null, JIT_R0, t_int);
	    new_label(fcode, next);
	    next = new_bnei_i(fcode, null, JIT_R0, t_float);
	    new_label(acode, next);
	    load_pointer(acode);
	    store_dynamic(acode, 0, type);
	    sync = lit_sync;
	    lit_sync = lit_sync_implicit;
	    if (!(sync & lit_sync_register))
		load_ireg_implicit(icode);
	    load_pointer(icode);
	    store_int(icode, 0, type);
	    lit_sync = lit_sync_implicit;
	    if (!(sync & lit_sync_register))
		load_freg_implicit(fcode);
	    load_pointer(fcode);
	    store_float(fcode, 0, type);
	    lit_type = t_any;
	    lit_sync = lit_sync_register|lit_sync_implicit;
	    break;
    }
    return (list);
#undef load_pointer
}
static east_list_t *
emit_sdt(east_list_t *list, east_node_t *node)
{
    list = parse_sdt(list, node);
    parse_flush(0);
    return (list);
}

static east_list_t *
parse_sb(east_list_t *list, east_node_t *node)
{
#define load_pointer(code)						\
    new_ldxi_p(code, JIT_R1, JIT_V0, offsetof(ethread_t, ebp))
    elit_node_t		*next;
    elit_node_t		*idone;
    elit_node_t		*fdone;
    eint32_t		 offset;
    offset = node->csymbol.symbol->offset * sizeof(evalue_t);
    switch (lit_type) {
	case t_int8:			case t_uint8:
	case t_int16:			case t_uint16:
	case t_int32:			case t_uint32:
	    if (!(lit_sync & lit_sync_int_ext)) {
		zero_sign_extend(icode, lit_type);
		lit_sync |= lit_sync_int_ext;
	    }
	case t_int:
	    load_pointer(icode);
	    store_ireg_value_type(icode, JIT_R1, offset);
	    break;
	case t_uint:
#if __WORDSIZE == 32
	    next = new_blti_i(icode, null, JIT_V2, 0);
#else
	    next = new_blti_l(icode, null, JIT_V1, 0);
#endif
	    if (!(lit_sync & lit_sync_implicit))
		store_ireg_implicit(icode, true);
	    load_pointer(icode);
	    store_ireg_value_type(icode, JIT_R1, offset);
	    new_label(acode, next);
	    idone = new_jmpi(icode, null);
#if __WORDSIZE == 32
	    store_ireg_implicit_rgz(acode, false, JIT_V1, JIT_V2);
#else
	    store_ireg_implicit_rgz(acode, false, JIT_V1);
#endif
	    call_i(acode, evm_sb, node->csymbol.symbol->offset);
	    new_label(acode, idone);
	    lit_sync = lit_sync_register|lit_sync_implicit;
	    lit_type = t_any;
	    break;
	case t_float32:
	    if (!(lit_sync & lit_sync_float_ext)) {
		float_extend(fcode, lit_type);
		lit_sync |= lit_sync_float_ext;
	    }
	case t_float:
	    load_pointer(fcode);
	    store_freg_value_type(fcode, JIT_R1, offset);
	    break;
	default:
	    new_ldxi_i(icode, JIT_R0, JIT_V0,
		       offsetof(ethread_t, r0) +  offsetof(evalue_t, t));
	    next = new_bnei_i(icode, null, JIT_R0, t_int);
	    if (!(lit_sync & lit_sync_register))
		load_ireg_implicit(icode);
	    load_pointer(icode);
	    store_ireg_value_type(icode, JIT_R1, offset);
	    idone = new_jmpi(icode, null);
	    new_label(fcode, next);
	    next = new_bnei_i(fcode, null, JIT_R0, t_float);
	    if (!(lit_sync & lit_sync_register))
		load_freg_implicit(fcode);
	    load_pointer(fcode);
	    store_freg_value_type(fcode, JIT_R1, offset);
	    fdone = new_jmpi(fcode, null);
	    new_label(acode, next);
	    call_i(acode, evm_sb, node->csymbol.symbol->offset);
	    new_label(acode, idone);
	    new_label(acode, fdone);
	    lit_sync = lit_sync_register|lit_sync_implicit;
	    break;
    }
    return (list);
#undef load_pointer
}
static east_list_t *
emit_sb(east_list_t *list, east_node_t *node)
{
    list = parse_sb(list, node);
    parse_flush(0);
    return (list);
}

static east_list_t *
parse_sbt(east_list_t *list, east_node_t *node)
{
#define load_pointer(code)						\
    new_ldxi_p(code, JIT_R1, JIT_V0, offsetof(ethread_t, ebp))
    elit_node_t		*next;
    eint32_t		 sync;
    eint32_t		 type;
    eint32_t		 offset;
    type = node->csymbol.symbol->type;
    offset = node->csymbol.symbol->offset * sizeof(evalue_t) +
	offsetof(evalue_t, v.o);
    switch (lit_type) {
	case t_int8:			case t_uint8:
	case t_int16:			case t_uint16:
	case t_int32:			case t_uint32:
	    load_pointer(icode);
	    store_int32(icode, offset, type);
	    break;
	case t_int:			case t_uint:
	    load_pointer(icode);
	    store_int(icode, offset, type);
	    break;
	case t_float32:
	    load_pointer(fcode);
	    store_float32(fcode, offset, type);
	    break;
	case t_float:
	    load_pointer(fcode);
	    store_float(fcode, offset, type);
	    break;
	default:
	    new_ldxi_i(icode, JIT_R0, JIT_V0,
		       offsetof(ethread_t, r0) +  offsetof(evalue_t, t));
	    next = new_bnei_i(icode, null, JIT_R0, t_int);
	    new_label(fcode, next);
	    next = new_bnei_i(fcode, null, JIT_R0, t_float);
	    new_label(acode, next);
	    load_pointer(acode);
	    store_dynamic(acode, offset, type);
	    sync = lit_sync;
	    lit_sync = lit_sync_implicit;
	    if (!(sync & lit_sync_register))
		load_ireg_implicit(icode);
	    load_pointer(icode);
	    store_int(icode, offset, type);
	    lit_sync = lit_sync_implicit;
	    if (!(sync & lit_sync_register))
		load_freg_implicit(fcode);
	    load_pointer(fcode);
	    store_float(fcode, offset, type);
	    lit_type = t_any;
	    lit_sync = lit_sync_register|lit_sync_implicit;
	    break;
    }
    return (list);
#undef load_pointer
}
static east_list_t *
emit_sbt(east_list_t *list, east_node_t *node)
{
    list = parse_sbt(list, node);
    parse_flush(0);
    return (list);
}

static east_list_t *
parse_ss(east_list_t *list, east_node_t *node, eobject_t function)
{
#define load_pointer(code)						\
    new_ldxi_p(code, JIT_R1, JIT_V0, offsetof(ethread_t, esp))
    elit_node_t		*next;
    elit_node_t		*idone;
    elit_node_t		*fdone;
    eint32_t		 offset;
    offset = node->cstack.offset * sizeof(evalue_t);
    switch (lit_type) {
	case t_int8:			case t_uint8:
	case t_int16:			case t_uint16:
	case t_int32:			case t_uint32:
	    if (!(lit_sync & lit_sync_int_ext)) {
		zero_sign_extend(icode, lit_type);
		lit_sync |= lit_sync_int_ext;
	    }
	case t_int:
	    load_pointer(icode);
	    store_ireg_value_type(icode, JIT_R1, offset);
	    break;
	case t_uint:
#if __WORDSIZE == 32
	    next = new_blti_i(icode, null, JIT_V2, 0);
#else
	    next = new_blti_l(icode, null, JIT_V1, 0);
#endif
	    if (!(lit_sync & lit_sync_implicit))
		store_ireg_implicit(icode, true);
	    load_pointer(icode);
	    store_ireg_value_type(icode, JIT_R1, offset);
	    new_label(acode, next);
	    idone = new_jmpi(icode, null);
#if __WORDSIZE == 32
	    store_ireg_implicit_rgz(acode, false, JIT_V1, JIT_V2);
#else
	    store_ireg_implicit_rgz(acode, false, JIT_V1);
#endif
	    call_i(acode, function, node->cstack.offset);
	    new_label(acode, idone);
	    lit_sync = lit_sync_register|lit_sync_implicit;
	    lit_type = t_any;
	    break;
	case t_float32:
	    if (!(lit_sync & lit_sync_float_ext)) {
		float_extend(fcode, lit_type);
		lit_sync |= lit_sync_float_ext;
	    }
	case t_float:
	    load_pointer(fcode);
	    store_freg_value_type(fcode, JIT_R1, offset);
	    break;
	default:
	    new_ldxi_i(icode, JIT_R0, JIT_V0,
		       offsetof(ethread_t, r0) +  offsetof(evalue_t, t));
	    next = new_bnei_i(icode, null, JIT_R0, t_int);
	    if (!(lit_sync & lit_sync_register))
		load_ireg_implicit(icode);
	    load_pointer(icode);
	    store_ireg_value_type(icode, JIT_R1, offset);
	    idone = new_jmpi(icode, null);
	    new_label(fcode, next);
	    next = new_bnei_i(fcode, null, JIT_R0, t_float);
	    if (!(lit_sync & lit_sync_register))
		load_freg_implicit(fcode);
	    load_pointer(fcode);
	    store_freg_value_type(fcode, JIT_R1, offset);
	    fdone = new_jmpi(fcode, null);
	    new_label(acode, next);
	    call_i(acode, function, node->cstack.offset);
	    new_label(acode, idone);
	    new_label(acode, fdone);
	    lit_sync = lit_sync_register|lit_sync_implicit;
	    break;
    }
    return (list);
#undef load_pointer
}
static east_list_t *
emit_ss(east_list_t *list, east_node_t *node)
{
    list = parse_ss(list, node, evm_ss);
    parse_flush(0);
    return (list);
}
static east_list_t *
emit_ssv(east_list_t *list, east_node_t *node)
{
    list = parse_ss(list, node, evm_ssv);
    parse_flush(0);
    return (list);
}

static east_list_t *
parse_sst(east_list_t *list, east_node_t *node)
{
#define load_pointer(code)						\
    new_ldxi_p(code, JIT_R1, JIT_V0, offsetof(ethread_t, esp));		\
    new_movi_i(code, JIT_R0, type);					\
    new_stxi_i(code, sizeof(evalue_t) * offset + offsetof(evalue_t, t),	\
	       JIT_R1, JIT_R0)
    elit_node_t		*next;
    eint32_t		 sync;
    eint32_t		 type;
    eint32_t		 offset;
    type = node->cstack.type;
    offset = node->cstack.offset * sizeof(evalue_t) + offsetof(evalue_t, v.o);
    switch (lit_type) {
	case t_int8:			case t_uint8:
	case t_int16:			case t_uint16:
	case t_int32:			case t_uint32:
	    load_pointer(icode);
	    store_int32(icode, offset, type);
	    break;
	case t_int:			case t_uint:
	    load_pointer(icode);
	    store_int(icode, offset, type);
	    break;
	case t_float32:
	    load_pointer(fcode);
	    store_float32(fcode, offset, type);
	    break;
	case t_float:
	    load_pointer(fcode);
	    store_float(fcode, offset, type);
	    break;
	default:
	    new_ldxi_i(icode, JIT_R0, JIT_V0,
		       offsetof(ethread_t, r0) +  offsetof(evalue_t, t));
	    next = new_bnei_i(icode, null, JIT_R0, t_int);
	    new_label(fcode, next);
	    next = new_bnei_i(fcode, null, JIT_R0, t_float);
	    new_label(acode, next);
	    load_pointer(acode);
	    store_dynamic(acode, offset, type);
	    sync = lit_sync;
	    lit_sync = lit_sync_implicit;
	    if (!(sync & lit_sync_register))
		load_ireg_implicit(icode);
	    load_pointer(icode);
	    store_int(icode, offset, type);
	    lit_sync = lit_sync_implicit;
	    if (!(sync & lit_sync_register))
		load_freg_implicit(fcode);
	    load_pointer(fcode);
	    store_float(fcode, offset, type);
	    lit_type = t_any;
	    lit_sync = lit_sync_register|lit_sync_implicit;
	    break;
    }
    return (list);
#undef load_pointer
}
static east_list_t *
emit_sst(east_list_t *list, east_node_t *node)
{
    list = parse_sst(list, node);
    parse_flush(0);
    return (list);
}

static east_list_t *
parse_sr(east_list_t *list, east_node_t *node)
{
#define load_pointer(code)						\
    new_ldxi_p(code, JIT_R0, JIT_V0, offsetof(ethread_t, esp));		\
    new_ldxi_i(code, JIT_R0, JIT_R0,					\
	       -sizeof(evalue_t) + offsetof(evalue_t, t));		\
    jump = new_beqi_i(code, null, JIT_R0, base);			\
    new_prepare(code, 3);						\
    new_movi_i(code, JIT_R1, offset);					\
    new_pusharg_i(code, JIT_R1);					\
    new_pusharg_i(code, JIT_R0);					\
    new_movi_i(code, JIT_R0, base);					\
    new_pusharg_i(code, JIT_R0);					\
    new_finish(code, evm_match_inheritance);				\
    if (lit_type == t_float32 || lit_type == t_float)			\
	load_freg_implicit(code);					\
    new_label(code, jump);						\
    new_ldxi_p(code, JIT_R1, JIT_V0, offsetof(ethread_t, esp));		\
    new_ldxi_p(code, JIT_R1, JIT_R1,					\
	       -sizeof(evalue_t) + offsetof(evalue_t, v.o))
#define sr_pop_stack(code)						\
    new_ldxi_p(code, JIT_R0, JIT_V0, offsetof(ethread_t, esp));		\
    new_subi_p(code, JIT_R0, JIT_R0, sizeof(evalue_t));			\
    new_stxi_p(code, offsetof(ethread_t, esp), JIT_V0, JIT_R0)
    elit_node_t		*jump;
    elit_node_t		*next;
    eint32_t		 base;
    eint32_t		 sync;
    eint32_t		 type;
    eint32_t		 offset;
    esymbol_t		*symbol;
    symbol = node->crecord.symbol;
    base = node->crecord.record->type;
    offset = symbol->offset;
    type = symbol->type;
    switch (lit_type) {
	case t_int8:			case t_uint8:
	case t_int16:			case t_uint16:
	case t_int32:			case t_uint32:
	    if (type == t_void || type > elast_basic_type)
		goto dynamic;
	    load_pointer(icode);
	    store_int32(icode, offset, type);
	    sr_pop_stack(icode);
	    break;
	case t_int:			case t_uint:
	    if (type == t_void || type > elast_basic_type)
		goto dynamic;
	    load_pointer(icode);
	    store_int(icode, offset, type);
	    sr_pop_stack(icode);
	    break;
	case t_float32:
	    if (type == t_void || type > elast_basic_type)
		goto dynamic;
	    load_pointer(fcode);
	    store_float32(fcode, offset, type);
	    sr_pop_stack(fcode);
	    break;
	case t_float:
	    if (type == t_void || type > elast_basic_type)
		goto dynamic;
	    load_pointer(fcode);
	    store_float(fcode, offset, type);
	    sr_pop_stack(fcode);
	    break;
	default:
	    switch (type) {
		case t_int8:		case t_uint8:
		case t_int16:		case t_uint16:
		case t_int32:		case t_uint32:
		case t_int:		case t_uint:
		case t_float32:		case t_float:
		    new_ldxi_i(icode, JIT_R0, JIT_V0,
			       offsetof(ethread_t, r0) +
			       offsetof(evalue_t, t));
		    next = new_bnei_i(icode, null, JIT_R0, t_int);
		    new_label(fcode, next);
		    next = new_bnei_i(fcode, null, JIT_R0, t_float);
		    new_label(acode, next);
		    load_pointer(acode);
		    store_dynamic(acode, offset, type);
		    sr_pop_stack(acode);
		    sync = lit_sync;
		    lit_sync = lit_sync_implicit;
		    if (!(sync & lit_sync_register))
			load_ireg_implicit(icode);
		    load_pointer(icode);
		    store_int(icode, offset, type);
		    sr_pop_stack(icode);
		    load_pointer(fcode);
		    lit_sync = lit_sync_implicit;
		    if (!(sync & lit_sync_register))
			load_freg_implicit(fcode);
		    store_float(fcode, offset, type);
		    sr_pop_stack(fcode);
		    lit_type = t_any;
		    lit_sync = lit_sync_register|lit_sync_implicit;
		    break;
		default:
		dynamic:
		    emit_sync(0);
		    call_v_i_i_i(evm_sr, base, offset, type);
		    break;
	    }
    }
    return (list);
#undef load_pointer
}
static east_list_t *
emit_sr(east_list_t *list, east_node_t *node)
{
    list = parse_sr(list, node);
    parse_flush(-1);
    return (list);
}

static east_list_t *
parse_sc(east_list_t *list, east_node_t *node)
{
#define load_pointer(code)						\
    new_ldxi_p(code, JIT_R1, JIT_V0, offsetof(ethread_t, ebp));		\
    new_ldxi_p(code, JIT_R1, JIT_R1,					\
	       -2 * sizeof(evalue_t) + offsetof(evalue_t, v.o))
    elit_node_t		*next;
    eint32_t		 sync;
    eint32_t		 type;
    eint32_t		 offset;
    type = node->csymbol.symbol->type;
    offset = node->csymbol.symbol->offset;
    switch (lit_type) {
	case t_int8:			case t_uint8:
	case t_int16:			case t_uint16:
	case t_int32:			case t_uint32:
	    if (type == t_void || type > elast_basic_type)
		goto dynamic;
	    load_pointer(icode);
	    store_int32(icode, offset, type);
	    break;
	case t_int:			case t_uint:
	    if (type == t_void || type > elast_basic_type)
		goto dynamic;
	    load_pointer(icode);
	    store_int(icode, offset, type);
	    break;
	case t_float32:
	    if (type == t_void || type > elast_basic_type)
		goto dynamic;
	    load_pointer(fcode);
	    store_float32(fcode, offset, type);
	    break;
	case t_float:
	    if (type == t_void || type > elast_basic_type)
		goto dynamic;
	    load_pointer(fcode);
	    store_float(fcode, offset, type);
	    break;
	default:
	    switch (type) {
		case t_int8:		case t_uint8:
		case t_int16:		case t_uint16:
		case t_int32:		case t_uint32:
		case t_int:		case t_uint:
		case t_float32:		case t_float:
		    new_ldxi_i(icode, JIT_R0, JIT_V0,
			       offsetof(ethread_t, r0) +
			       offsetof(evalue_t, t));
		    next = new_bnei_i(icode, null, JIT_R0, t_int);
		    new_label(fcode, next);
		    next = new_bnei_i(fcode, null, JIT_R0, t_float);
		    new_label(acode, next);
		    load_pointer(acode);
		    store_dynamic(acode, offset, type);
		    sync = lit_sync;
		    lit_sync = lit_sync_implicit;
		    if (!(sync & lit_sync_register))
			load_ireg_implicit(icode);
		    load_pointer(icode);
		    store_int(icode, offset, type);
		    lit_sync = lit_sync_implicit;
		    if (!(sync & lit_sync_register))
			load_freg_implicit(fcode);
		    load_pointer(fcode);
		    store_float(fcode, offset, type);
		    lit_type = t_any;
		    lit_sync = lit_sync_register|lit_sync_implicit;
		    break;
		default:
		dynamic:
		    emit_sync(0);
		    call_v_i_i(evm_sc, offset, type);
		    break;
	    }
    }
    return (list);
#undef load_pointer
}
static east_list_t *
emit_sc(east_list_t *list, east_node_t *node)
{
    list = parse_sc(list, node);
    parse_flush(0);
    return (list);
}

static east_list_t *
parse_push(east_list_t *list, east_node_t *node, eobject_t function)
{
    elit_node_t		*next;
    elit_node_t		*idone;
    elit_node_t		*fdone;
    switch (lit_type) {
	case t_int8:			case t_uint8:
	case t_int16:			case t_uint16:
	case t_int32:			case t_uint32:
	    if (!(lit_sync & lit_sync_int_ext)) {
		zero_sign_extend(icode, lit_type);
		lit_sync |= lit_sync_int_ext;
	    }
	case t_int:
	    push_ireg(icode);
	    push_type(lit_type);
	    break;
	case t_uint:
#if __WORDSIZE == 32
	    next = new_blti_i(icode, null, JIT_V2, 0);
#else
	    next = new_blti_l(icode, null, JIT_V1, 0);
#endif
	    if (!(lit_sync & lit_sync_implicit))
		store_ireg_implicit(icode, true);
	    push_ireg(icode);
	    new_label(acode, next);
	    idone = new_jmpi(icode, null);
#if __WORDSIZE == 32
	    store_ireg_implicit_rgz(acode, false, JIT_V1, JIT_V2);
#else
	    store_ireg_implicit_rgz(acode, false, JIT_V1);
#endif
	    new_calli(acode, function);
	    new_label(acode, idone);
	    push_type(t_any);
	    lit_sync = lit_sync_register|lit_sync_implicit;
	    lit_type = t_any;
	    break;
	case t_float32:
	    if (!(lit_sync & lit_sync_float_ext)) {
		float_extend(fcode, lit_type);
		lit_sync |= lit_sync_float_ext;
	    }
	case t_float:
	    push_freg(fcode);
	    push_type(t_float);
	    break;
	default:
	    new_ldxi_i(icode, JIT_R0, JIT_V0,
		       offsetof(ethread_t, r0) +  offsetof(evalue_t, t));
	    next = new_bnei_i(icode, null, JIT_R0, t_int);
	    if (!(lit_sync & lit_sync_register))
		load_ireg_implicit(icode);
	    push_ireg(icode);
	    idone = new_jmpi(icode, null);
	    new_label(fcode, next);
	    next = new_bnei_i(fcode, null, JIT_R0, t_float);
	    if (!(lit_sync & lit_sync_register))
		load_freg_implicit(fcode);
	    push_freg(fcode);
	    fdone = new_jmpi(fcode, null);
	    new_label(acode, next);
	    new_calli(acode, function);
	    new_label(acode, idone);
	    new_label(acode, fdone);
	    push_type(t_any);
	    lit_sync = lit_sync_register|lit_sync_implicit;
	    break;
    }
    return (list);
}
static east_list_t *
emit_push(east_list_t *list, east_node_t *node)
{
    list = parse_push(list, node, evm_push);
    parse_flush(0);
    return (list);
}
static east_list_t *
emit_pushv(east_list_t *list, east_node_t *node)
{
    list = parse_push(list, node, evm_pushv);
    parse_flush(0);
    return (list);
}

static east_list_t *
parse_pusht(east_list_t *list, east_node_t *node)
{
#define load_pointer(code)						\
    new_ldxi_p(code, JIT_R1, JIT_V0, offsetof(ethread_t, esp));		\
    new_addi_p(code, JIT_R0, JIT_R1, sizeof(evalue_t));			\
    new_stxi_p(code, offsetof(ethread_t, esp), JIT_V0, JIT_R0);		\
    new_movi_i(code, JIT_R0, type);					\
    new_stxi_i(code, offsetof(evalue_t, t), JIT_R1, JIT_R0)
    elit_node_t		*next;
    eint32_t		 sync;
    eint32_t		 type;
    eint32_t		 offset;
    type = node->cstack.type;
    offset = offsetof(evalue_t, v.o);
    switch (lit_type) {
	case t_int8:			case t_uint8:
	case t_int16:			case t_uint16:
	case t_int32:			case t_uint32:
	    load_pointer(icode);
	    store_int32(icode, offset, type);
	    break;
	case t_int:			case t_uint:
	    load_pointer(icode);
	    store_int(icode, offset, type);
	    break;
	case t_float32:
	    load_pointer(fcode);
	    store_float32(fcode, offset, type);
	    break;
	case t_float:
	    load_pointer(fcode);
	    store_float(fcode, offset, type);
	    break;
	default:
	    new_ldxi_i(icode, JIT_R0, JIT_V0,
		       offsetof(ethread_t, r0) +  offsetof(evalue_t, t));
	    next = new_bnei_i(icode, null, JIT_R0, t_int);
	    new_label(fcode, next);
	    next = new_bnei_i(fcode, null, JIT_R0, t_float);
	    new_label(acode, next);
	    load_pointer(acode);
	    store_dynamic(acode, offset, type);
	    sync = lit_sync;
	    lit_sync = lit_sync_implicit;
	    if (!(sync & lit_sync_register))
		load_ireg_implicit(icode);
	    load_pointer(icode);
	    store_int(icode, offset, type);
	    lit_sync = lit_sync_implicit;
	    if (!(sync & lit_sync_register))
		load_freg_implicit(fcode);
	    load_pointer(fcode);
	    store_float(fcode, offset, type);
	    lit_type = t_any;
	    lit_sync = lit_sync_register|lit_sync_implicit;
	    break;
    }
    return (list);
#undef load_pointer
}
static east_list_t *
emit_pusht(east_list_t *list, east_node_t *node)
{
    list = parse_pusht(list, node);
    parse_flush(1);
    return (list);
}

static void
parse_inc_int32(void)
{
#if __WORDSIZE == 32
    elit_node_t		*done;
    elit_node_t		*over;
    over = new_boaddi_ui(icode, null, JIT_V1, 1);
    done = new_jmpi(icode, null);
    new_label(icode, over);
    new_addi_i(icode, JIT_V2, JIT_V2, 1);
    new_label(icode, done);
#else
    new_addi_l(icode, JIT_V1, JIT_V1, 1);
#endif
}
static void
parse_inc_int(void)
{
    elit_node_t		*done;
    elit_node_t		*over;
#if __WORDSIZE == 32
    new_movr_i(icode, JIT_R0, JIT_V1);
    over = new_boaddi_ui(icode, null, JIT_V1, 1);
    done = new_jmpi(icode, null);
    new_label(icode, over);
    new_movr_i(icode, JIT_R2, JIT_V2);
    over = new_boaddi_i(icode, null, JIT_V2, 1);
    new_label(icode, done);
    store_ireg_implicit(icode, true);
    done = new_jmpi(icode, null);
    new_label(icode, over);
    store_ireg_implicit_rgz(icode, true, JIT_R0, JIT_R2);
#else
    new_movr_l(icode, JIT_R0, JIT_V1);
    over = new_boaddi_l(icode, null, JIT_V1, 1);
    store_ireg_implicit(icode, true);
    done = new_jmpi(icode, null);
    new_label(icode, over);
    store_ireg_implicit_rgz(icode, true, JIT_R0);
#endif
    parse_inc_mpz();
    new_label(acode, done);
    if (lit_type == t_any) {
	done = new_jmpi(icode, null);
	new_label(acode, done);
    }
}
static void
parse_inc_uint(void)
{
    elit_node_t		*done;
    elit_node_t		*over;
#if __WORDSIZE == 32
    new_movr_i(icode, JIT_R0, JIT_V1);
    new_movr_i(icode, JIT_R2, JIT_V2);
    new_addci_ui(icode, JIT_V1, JIT_V1, 1);
    new_addxi_ui(icode, JIT_V2, JIT_V2, 0);
    over = new_blti_i(icode, null, JIT_V2, 0);
    store_ireg_implicit(icode, true);
    done = new_jmpi(icode, null);
    new_label(icode, over);
    store_ireg_implicit_rgz(icode, false, JIT_R0, JIT_R2);
#else
    new_movr_l(icode, JIT_R0, JIT_V1);
    new_addi_l(icode, JIT_V1, JIT_V1, 1);
    over = new_blti_l(icode, null, JIT_V1, 0);
    store_ireg_implicit(icode, true);
    done = new_jmpi(icode, null);
    new_label(icode, over);
    store_ireg_implicit_rgz(icode, false, JIT_R0);
#endif
    parse_inc_mpz();
    new_label(acode, done);
}
static void
parse_inc_mpz(void)
{
    new_prepare(icode, 3);
    new_movi_i(icode, JIT_R0, 1);
    new_pusharg_i(icode, JIT_R0);
    new_pusharg_p(icode, JIT_V1);
    new_pusharg_p(icode, JIT_V1);
    new_finish(icode, mpz_add_ui);
}
static void
parse_inc_float(void)
{
    elit_node_t		*done;
    new_movi_d(fcode, JIT_FPR1, 1.0);
    new_addr_d(fcode, JIT_FPR0, JIT_FPR0, JIT_FPR1);
    if (lit_type == t_any) {
	store_freg_implicit(fcode, true);
	done = new_jmpi(fcode, null);
	new_label(acode, done);
    }
}
static east_list_t *
parse_inc(east_list_t *list, east_node_t *node)
{
    elit_node_t		*next;
    switch (lit_type) {
	case t_int8:			case t_uint8:
	    lit_type = t_int16;
	    goto inc_int16;
	case t_int16:			case t_uint16:
	    lit_type = t_int32;
	inc_int16:
#if __WORDSIZE == 32
	    new_addi_i(icode, JIT_V1, JIT_V1, 1);
#else
	    new_addi_l(icode, JIT_V1, JIT_V1, 1);
#endif
	    lit_sync = lit_sync_register;
	    break;
	case t_int32:			case t_uint32:
	    if (!(lit_sync & lit_sync_int_ext))
		zero_sign_extend(icode, lit_type);
	    parse_inc_int32();
	    lit_sync = lit_sync_register|lit_sync_int_ext;
	    lit_type = t_int;
	    break;
	case t_int:
	    parse_inc_int();
	    lit_sync = lit_sync_register|lit_sync_implicit;
	    lit_type = t_any;
	    break;
	case t_uint:
	    parse_inc_uint();
	    lit_sync = lit_sync_register|lit_sync_implicit;
	    lit_type = t_any;
	    break;
	case t_float32:
	    if (!(lit_sync_float_ext))
		float_extend(fcode, lit_type);
	    /* increment only float */
	    lit_type = t_float;
	case t_float:
	    parse_inc_float();
	    lit_sync = lit_sync_register;
	    break;
	default:
	    new_ldxi_i(icode, JIT_R0, JIT_V0,
		       offsetof(ethread_t, r0) +  offsetof(evalue_t, t));
	    next = new_bnei_i(icode, null, JIT_R0, t_int);
	    new_label(fcode, next);
	    next = new_bnei_i(fcode, null, JIT_R0, t_float);
	    new_label(acode, next);
	    new_calli(acode, evm_inc);
	    if (!(lit_sync & lit_sync_register))
		load_ireg_implicit(icode);
	    parse_inc_int();
	    if (!(lit_sync & lit_sync_register))
		load_freg_implicit(fcode);
	    parse_inc_float();
	    /* register not synced if mpz change to int */
	    lit_sync = lit_sync_implicit;
	    break;
    }
    return (list);
}
static east_list_t *
emit_inc(east_list_t *list, east_node_t *node)
{
    list = parse_inc(list, node);
    parse_flush(0);
    return (list);
}

static void
parse_dec_int32(void)
{
#if __WORDSIZE == 32
    elit_node_t		*done;
    elit_node_t		*over;
    over = new_bosubi_ui(icode, null, JIT_V1, 1);
    done = new_jmpi(icode, null);
    new_label(icode, over);
    new_subi_i(icode, JIT_V2, JIT_V2, 1);
    new_label(icode, done);
#else
    new_subi_l(icode, JIT_V1, JIT_V1, 1);
#endif
}
static void
parse_dec_int(void)
{
    elit_node_t		*done;
    elit_node_t		*over;
#if __WORDSIZE == 32
    new_movr_i(icode, JIT_R0, JIT_V1);
    over = new_bosubi_ui(icode, null, JIT_V1, 1);
    done = new_jmpi(icode, null);
    new_label(icode, over);
    new_movr_i(icode, JIT_R2, JIT_V2);
    over = new_bosubi_i(icode, null, JIT_V2, 1);
    new_label(icode, done);
    store_ireg_implicit(icode, true);
    done = new_jmpi(icode, null);
    new_label(icode, over);
    store_ireg_implicit_rgz(icode, true, JIT_R0, JIT_R2);
#else
    new_movr_l(icode, JIT_R0, JIT_V1);
    over = new_bosubi_l(icode, null, JIT_V1, 1);
    store_ireg_implicit(icode, true);
    done = new_jmpi(icode, null);
    new_label(icode, over);
    store_ireg_implicit_rgz(icode, true, JIT_R0);
#endif
    parse_dec_mpz();
    new_label(acode, done);
    if (lit_type == t_any) {
	done = new_jmpi(icode, null);
	new_label(acode, done);
    }
}
static void
parse_dec_uint(void)
{
    elit_node_t		*done;
    elit_node_t		*over;
#if __WORDSIZE == 32
    new_movr_i(icode, JIT_R0, JIT_V1);
    new_movr_i(icode, JIT_R2, JIT_V2);
    new_subci_ui(icode, JIT_V1, JIT_V1, 1);
    new_subxi_ui(icode, JIT_V2, JIT_V2, 0);
    over = new_blti_i(icode, null, JIT_V2, 0);
    store_ireg_implicit(icode, true);
    done = new_jmpi(icode, null);
    new_label(icode, over);
    store_ireg_implicit_rgz(icode, false, JIT_R0, JIT_R2);
#else
    new_movr_l(icode, JIT_R0, JIT_V1);
    new_subi_l(icode, JIT_V1, JIT_V1, 1);
    over = new_blti_l(icode, null, JIT_V1, 0);
    store_ireg_implicit(icode, true);
    done = new_jmpi(icode, null);
    new_label(icode, over);
    store_ireg_implicit_rgz(icode, false, JIT_R0);
#endif
    parse_dec_mpz();
    new_label(acode, done);
}
static void
parse_dec_mpz(void)
{
    new_prepare(icode, 3);
    new_movi_i(icode, JIT_R0, 1);
    new_pusharg_i(icode, JIT_R0);
    new_pusharg_p(icode, JIT_V1);
    new_pusharg_p(icode, JIT_V1);
    new_finish(icode, mpz_sub_ui);
}
static void
parse_dec_float(void)
{
    elit_node_t		*done;
    new_movi_d(fcode, JIT_FPR1, 1.0);
    new_subr_d(fcode, JIT_FPR0, JIT_FPR0, JIT_FPR1);
    if (lit_type == t_any) {
	store_freg_implicit(fcode, true);
	done = new_jmpi(fcode, null);
	new_label(acode, done);
    }
}
static east_list_t *
parse_dec(east_list_t *list, east_node_t *node)
{
    elit_node_t		*next;
    switch (lit_type) {
	case t_int8:			case t_uint8:
	    lit_type = t_int16;
	    goto inc_int16;
	case t_int16:			case t_uint16:
	    lit_type = t_int32;
	inc_int16:
#if __WORDSIZE == 32
	    new_subi_i(icode, JIT_V1, JIT_V1, 1);
#else
	    new_subi_l(icode, JIT_V1, JIT_V1, 1);
#endif
	    lit_sync = lit_sync_register;
	    break;
	case t_int32:			case t_uint32:
	    if (!(lit_sync & lit_sync_int_ext))
		zero_sign_extend(icode, lit_type);
	    parse_dec_int32();
	    lit_sync = lit_sync_register|lit_sync_int_ext;
	    lit_type = t_int;
	    break;
	case t_int:
	    parse_dec_int();
	    lit_sync = lit_sync_register|lit_sync_implicit;
	    lit_type = t_any;
	    break;
	case t_uint:
	    parse_dec_uint();
	    lit_sync = lit_sync_register|lit_sync_implicit;
	    lit_type = t_any;
	    break;
	case t_float32:
	    if (!(lit_sync_float_ext))
		float_extend(fcode, lit_type);
	    /* decrement only float */
	    lit_type = t_float;
	case t_float:
	    parse_dec_float();
	    lit_sync = lit_sync_register;
	    break;
	default:
	    new_ldxi_i(icode, JIT_R0, JIT_V0,
		       offsetof(ethread_t, r0) +  offsetof(evalue_t, t));
	    next = new_bnei_i(icode, null, JIT_R0, t_int);
	    new_label(fcode, next);
	    next = new_bnei_i(fcode, null, JIT_R0, t_float);
	    new_label(acode, next);
	    new_calli(acode, evm_dec);
	    if (!(lit_sync & lit_sync_register))
		load_ireg_implicit(icode);
	    parse_dec_int();
	    if (!(lit_sync & lit_sync_register))
		load_freg_implicit(fcode);
	    parse_dec_float();
	    /* register not synced if mpz change to int */
	    lit_sync = lit_sync_implicit;
	    break;
    }
    return (list);
}
static east_list_t *
emit_dec(east_list_t *list, east_node_t *node)
{
    list = parse_dec(list, node);
    parse_flush(0);
    return (list);
}

#if __WORDSIZE == 32
#  define load_result(code)						\
    new_ldxi_i(code, JIT_V1, JIT_V0,					\
	       offsetof(ethread_t, r0) + offsetof(evalue_t, v.i) +	\
	       offsetof(edata_t, s.l));					\
    new_movi_i(code, JIT_V2, 0)
#  define store_result(code)						\
    new_movi_i(code, JIT_V2, 0);					\
    store_ireg_implicit(code, true)
#else
#  define load_result(code)						\
    new_ldxi_l(code, JIT_V1, JIT_V0,					\
	       offsetof(ethread_t, r0) + offsetof(evalue_t, v.i))
#  define store_result(code)						\
    store_ireg_implicit(code, true)
#endif
static void
cmp_int32_int32(eint32_t code, ecode_t opcode)
{
    new_ldxi_i(code, JIT_R0, JIT_R1,
	       -sizeof(evalue_t) + offsetof(evalue_t, v.i) +
	       offsetof(edata_t, s.l));
#if defined(__i386__) || defined(__x86_64__)
    /* avoid worst case comparison logic; not so bad for x86_64,
     * but still generates better code if using 3 registers */
    switch (opcode) {
	case eop_ne:	new_ner_i(code, JIT_R2, JIT_R0, JIT_V1);	break;
	case eop_lt:	new_ltr_i(code, JIT_R2, JIT_R0, JIT_V1);	break;
	case eop_le:	new_ler_i(code, JIT_R2, JIT_R0, JIT_V1);	break;
	case eop_eq:	new_eqr_i(code, JIT_R2, JIT_R0, JIT_V1);	break;
	case eop_ge:	new_ger_i(code, JIT_R2, JIT_R0, JIT_V1);	break;
	default:	new_gtr_i(code, JIT_R2, JIT_R0, JIT_V1);	break;
    }
    new_movr_i(code, JIT_V1, JIT_R2);
#else
    switch (opcode) {
	case eop_ne:	new_ner_i(code, JIT_V1, JIT_R0, JIT_V1);	break;
	case eop_lt:	new_ltr_i(code, JIT_V1, JIT_R0, JIT_V1);	break;
	case eop_le:	new_ler_i(code, JIT_V1, JIT_R0, JIT_V1);	break;
	case eop_eq:	new_eqr_i(code, JIT_V1, JIT_R0, JIT_V1);	break;
	case eop_ge:	new_ger_i(code, JIT_V1, JIT_R0, JIT_V1);	break;
	default:	new_gtr_i(code, JIT_V1, JIT_R0, JIT_V1);	break;
    }
#endif
}
static void
cmp_int32_float(eint32_t code, eint32_t opcode)
{
    new_ldxi_i(code, JIT_R0, JIT_R1,
	       -sizeof(evalue_t) + offsetof(evalue_t, v.i) +
	       offsetof(edata_t, s.l));
    new_extr_i_d(code, JIT_FPR2, JIT_R0);
    cmp_inner_float_float(code, opcode);
}
static void
cmp_int_int(eint32_t code, eint32_t opcode)
{
#if __WORDSIZE == 32
    elit_node_t		*done;
    new_ldxi_i(code, JIT_R0, JIT_R1,
	       -sizeof(evalue_t) + offsetof(evalue_t, v.i) +
	       offsetof(edata_t, s.l));
    switch (opcode) {
#  if defined(__i386__)
	case eop_ne:
	    new_ner_i(code, JIT_R2, JIT_R0, JIT_V1);
	    done = new_bnei_i(code, null, JIT_R2, 0);
	    break;
	case eop_eq:
	    new_eqr_i(code, JIT_R2, JIT_R0, JIT_V1);
	    done = new_beqi_i(code, null, JIT_R2, 0);
	    break;
#  else
	case eop_ne:
	    new_ner_i(code, JIT_V1, JIT_R0, JIT_V1);
	    done = new_bnei_i(code, null, JIT_V1, 0);
	    break;
	case eop_eq:
	    new_eqr_i(code, JIT_V1, JIT_R0, JIT_V1);
	    done = new_beqi_i(code, null, JIT_V1, 0);
	    break;
#  endif
	default:
	    new_ldxi_i(code, JIT_R2, JIT_R1,
		       -sizeof(evalue_t) + offsetof(evalue_t, v.i) +
		       offsetof(edata_t, s.h));
	    break;
    }
    if (opcode == eop_ne || opcode == eop_eq)
	new_ldxi_i(code, JIT_R0, JIT_R1,
		   -sizeof(evalue_t) + offsetof(evalue_t, v.i) +
		   offsetof(edata_t, s.h));
    switch (opcode) {
	case eop_lt:
	    new_subcr_ui(code, JIT_R0, JIT_R0, JIT_V1);
	    new_subxr_ui(code, JIT_R2, JIT_R2, JIT_V2);
	    break;
	case eop_le:
	    new_subcr_ui(code, JIT_V1, JIT_V1, JIT_R0);
	    new_subxr_ui(code, JIT_V2, JIT_V2, JIT_R2);
	    break;
	case eop_ge:
	    new_subcr_ui(code, JIT_R0, JIT_R0, JIT_V1);
	    new_subxr_ui(code, JIT_R2, JIT_R2, JIT_V2);
	    break;
	case eop_gt:
	    new_subcr_ui(code, JIT_V1, JIT_V1, JIT_R0);
	    new_subxr_ui(code, JIT_V2, JIT_V2, JIT_R2);
	    break;
	default:
	    break;
    }
#  if defined(__i386__)
    switch (opcode) {
	case eop_ne:	new_ner_i(code, JIT_R2, JIT_R0, JIT_V2);	break;
	case eop_lt:	new_lti_i(code, JIT_R0, JIT_R2, 0);		break;
	case eop_le:	new_gei_i(code, JIT_R0, JIT_V2, 0);		break;
	case eop_eq:	new_eqr_i(code, JIT_R2, JIT_R0, JIT_V2);	break;
	case eop_ge:	new_gei_i(code, JIT_R0, JIT_R2, 0);		break;
	default:	new_lti_i(code, JIT_R0, JIT_V2, 0);		break;
    }
    if (opcode == eop_ne || opcode == eop_eq) {
	new_label(code, done);
	new_movr_i(code, JIT_V1, JIT_R2);
    }
    else
	new_movr_i(code, JIT_V1, JIT_R0);
#  else
    switch (opcode) {
	case eop_ne:	new_ner_i(code, JIT_V1, JIT_R0, JIT_V2);	break;
	case eop_lt:	new_lti_i(code, JIT_V1, JIT_R2, 0);		break;
	case eop_le:	new_gei_i(code, JIT_V1, JIT_V2, 0);		break;
	case eop_eq:	new_eqr_i(code, JIT_V1, JIT_R0, JIT_V2);	break;
	case eop_ge:	new_gei_i(code, JIT_V1, JIT_R2, 0);		break;
	default:	new_lti_i(code, JIT_V1, JIT_V2, 0);		break;
    }
    if (opcode == eop_ne || opcode == eop_eq)
	new_label(code, done);
#  endif
#else
    new_ldxi_l(code, JIT_R0, JIT_R1,
	       -sizeof(evalue_t) + offsetof(evalue_t, v.i));
#  if defined(__x86_64__)
    switch (opcode) {
	case eop_ne:	new_ner_l(code, JIT_R2, JIT_R0, JIT_V1);	break;
	case eop_lt:	new_ltr_l(code, JIT_R2, JIT_R0, JIT_V1);	break;
	case eop_le:	new_ler_l(code, JIT_R2, JIT_R0, JIT_V1);	break;
	case eop_eq:	new_eqr_l(code, JIT_R2, JIT_R0, JIT_V1);	break;
	case eop_ge:	new_ger_l(code, JIT_R2, JIT_R0, JIT_V1);	break;
	default:	new_gtr_l(code, JIT_R2, JIT_R0, JIT_V1);	break;
    }
    new_movr_l(code, JIT_V1, JIT_R2);
#  else
    switch (opcode) {
	case eop_ne:	new_ner_l(code, JIT_V1, JIT_R0, JIT_V1);	break;
	case eop_lt:	new_ltr_l(code, JIT_V1, JIT_R0, JIT_V1);	break;
	case eop_le:	new_ler_l(code, JIT_V1, JIT_R0, JIT_V1);	break;
	case eop_eq:	new_eqr_l(code, JIT_V1, JIT_R0, JIT_V1);	break;
	case eop_ge:	new_ger_l(code, JIT_V1, JIT_R0, JIT_V1);	break;
	default:	new_gtr_l(code, JIT_V1, JIT_R0, JIT_V1);	break;
    }
#  endif
#endif
}
static void
cmp_any_int(eint32_t code, ecode_t opcode, elit_node_t *fail)
{
#if __WORDSIZE == 64
    elit_node_t		*done;
    elit_node_t		*next;
#endif
    new_ldxi_i(code, JIT_R0, JIT_R1,
	       -sizeof(evalue_t) + offsetof(evalue_t, t));
#if __WORDSIZE == 32
    new_bnei_i(code, fail, JIT_R0, t_int);
    if (!(lit_sync & lit_sync_register))
	load_ireg_implicit(code);
    cmp_int_int(code, opcode);
#else
    next = new_bnei_i(code, null, JIT_R0, t_int);
    if (!(lit_sync & lit_sync_register))
	load_ireg_implicit(code);
    cmp_int_int(code, opcode);
    done = new_jmpi(code, null);
    new_label(code, next);
    new_bnei_i(code, fail, JIT_R0, t_float);
    if (!(lit_sync & lit_sync_register))
	load_ireg_implicit(code);
    if (!(lit_sync & lit_sync_long_double))
	new_extr_l_d(code, JIT_FPR0, JIT_V1);
    new_ldxi_d(code, JIT_FPR2, JIT_R1,
	       -sizeof(evalue_t) + offsetof(evalue_t, v.d));
    cmp_inner_float_float(code, opcode);
    new_label(code, done);
#endif
}
#if __WORDSIZE == 64
static void
cmp_int_float(eint32_t code, ecode_t opcode)
{
    new_ldxi_l(code, JIT_R0, JIT_R1,
	       -sizeof(evalue_t) + offsetof(evalue_t, v.i));
    new_extr_l_d(code, JIT_FPR2, JIT_R0);
    cmp_inner_float_float(code, opcode);
}
#endif
static void
cmp_inner_float_float(eint32_t code, ecode_t opcode)
{
    switch (opcode) {
	case eop_ne:	new_ner_d(code, JIT_V1, JIT_FPR2, JIT_FPR0);	break;
	case eop_lt:	new_ltr_d(code, JIT_V1, JIT_FPR2, JIT_FPR0);	break;
	case eop_le:	new_ler_d(code, JIT_V1, JIT_FPR2, JIT_FPR0);	break;
	case eop_eq:	new_eqr_d(code, JIT_V1, JIT_FPR2, JIT_FPR0);	break;
	case eop_ge:	new_ger_d(code, JIT_V1, JIT_FPR2, JIT_FPR0);	break;
	default:	new_gtr_d(code, JIT_V1, JIT_FPR2, JIT_FPR0);	break;
    }
}
static void
cmp_float_float(eint32_t code, ecode_t opcode)
{
    new_ldxi_d(code, JIT_FPR2, JIT_R1,
	       -sizeof(evalue_t) + offsetof(evalue_t, v.d));
    cmp_inner_float_float(code, opcode);
}
static void
cmp_any_float32(eint32_t code, ecode_t opcode, elit_node_t *fail)
{
    new_ldxi_i(code, JIT_R0, JIT_R1,
	       -sizeof(evalue_t) + offsetof(evalue_t, t));
    new_bnei_i(code, fail, JIT_R0, t_float);
    if (!(lit_sync & lit_sync_float_ext))
	new_extr_f_d(code, JIT_FPR0, JIT_FPR1);
    cmp_float_float(code, opcode);
}
static void
cmp_any_float(eint32_t code, ecode_t opcode, elit_node_t *fail)
{
    new_ldxi_i(code, JIT_R0, JIT_R1,
	       -sizeof(evalue_t) + offsetof(evalue_t, t));
    new_bnei_i(code, fail, JIT_R0, t_float);
    if (!(lit_sync & lit_sync_register))
	load_freg_implicit(code);
    cmp_float_float(code, opcode);
}
static void
cmp_any_any(eint32_t code, eint32_t opcode)
{
    switch (opcode) {
	case eop_ne:	new_calli(code, evm_ne);	break;
	case eop_lt:	new_calli(code, evm_lt);	break;
	case eop_le:	new_calli(code, evm_le);	break;
	case eop_eq:	new_calli(code, evm_eq);	break;
	case eop_ge:	new_calli(code, evm_ge);	break;
	default:	new_calli(code, evm_gt);	break;
    }
}
static east_list_t *
parse_cmp(east_list_t *list, east_node_t *node)
{
    elit_node_t		*done;
    elit_node_t		*next;
    elit_node_t		*fail;
    switch (top_type()) {
	case t_int8:			case t_uint8:
	case t_int16:			case t_uint16:
	case t_int32:
	    switch (lit_type) {
		case t_int8:		case t_uint8:
		case t_int16:		case t_uint16:
		case t_int32:
		    load_stack(icode);
		    cmp_int32_int32(icode, node->code);
		    pop_stack(icode);
		    lit_sync = lit_sync_register;
		    break;
		case t_uint32:
		    goto int32_int32;
		case t_int:		case t_uint:
		    goto int_int;
		case t_float32:
		    if (!(lit_sync & lit_sync_float_ext))
			new_extr_f_d(icode, JIT_FPR0, JIT_FPR1);
		case t_float:
		    load_stack(icode);
		    cmp_int32_float(icode, node->code);
		    pop_stack(icode);
		    lit_sync = lit_sync_register;
		    break;
		default:
		    cmp_any_any(acode, node->code);
		    load_result(acode);
		    lit_sync = lit_sync_register|
			lit_sync_implicit|lit_sync_int_ext;
		    break;
	    }
	    break;
	case t_uint32:			case t_int:
	    switch (lit_type) {
		case t_int8:		case t_uint8:
		case t_int16:		case t_uint16:
		case t_int32:		case t_uint32:
		int32_int32:
		    if (!(lit_sync & lit_sync_int_ext))
			zero_sign_extend(icode, lit_type);
		case t_int:		case t_uint:
		int_int:
		    load_stack(icode);
		    cmp_int_int(icode, node->code);
		    pop_stack(icode);
		    lit_sync = lit_sync_register;
		    break;
#if __WORDSIZE == 64
		case t_float32:
		    if (!(lit_sync & lit_sync_float_ext))
			new_extr_f_d(icode, JIT_FPR0, JIT_FPR1);
		case t_float:
		    load_stack(icode);
		    cmp_int_float(icode, node->code);
		    pop_stack(icode);
		    lit_sync = lit_sync_register;
		    break;
#else
		case t_float32:
		    if (!(lit_sync & lit_sync_float_ext))
			new_extr_f_d(acode, JIT_FPR0, JIT_FPR1);
		case t_float:
		    if (!(lit_sync & lit_sync_implicit))
			store_freg_implicit(acode, true);
#endif
		default:
		    cmp_any_any(acode, node->code);
		    load_result(acode);
		    lit_sync = lit_sync_register|
			lit_sync_implicit|lit_sync_int_ext;
		    break;
	    }
	    break;
	case t_float:
	    switch (lit_type) {
		case t_int8:		case t_uint8:
		case t_int16:		case t_uint16:
		case t_int32:
		    if (!(lit_sync & lit_sync_int_double))
			new_extr_i_d(fcode, JIT_FPR0, JIT_V1);
		    load_stack(fcode);
		    cmp_float_float(fcode, node->code);
		    pop_stack(fcode);
		    lit_sync = lit_sync_register;
		    break;
#if __WORDSIZE == 64
		case t_uint32:		case t_int:
		    if (!(lit_sync & lit_sync_long_double))
			new_extr_l_d(fcode, JIT_FPR0, JIT_V1);
		    load_stack(fcode);
		    cmp_float_float(fcode, node->code);
		    pop_stack(fcode);
		    lit_sync = lit_sync_register;
		    break;
#endif
		case t_float32:
		    if (!(lit_sync & lit_sync_float_ext))
			new_extr_f_d(fcode, JIT_FPR0, JIT_FPR1);
		case t_float:
		    load_stack(fcode);
		    cmp_float_float(fcode, node->code);
		    pop_stack(fcode);
		    lit_sync = lit_sync_register;
		    break;
#if __WORDSIZE == 64
		case t_uint:
		    next = new_blti_l(fcode, null, JIT_V1, 0);
		    if (!(lit_sync & lit_sync_long_double))
			new_extr_l_d(fcode, JIT_FPR0, JIT_V1);
		    load_stack(fcode);
		    cmp_float_float(fcode, node->code);
		    pop_stack(fcode);
		    store_ireg_implicit(fcode, true);
		    done = new_jmpi(fcode, null);
		    new_label(acode, next);
		    store_ireg_implicit_rgz(acode, false, JIT_V1);
		    cmp_any_any(acode, node->code);
		    load_result(acode);
		    new_label(acode, done);
		    lit_sync = lit_sync_register|
			lit_sync_implicit|lit_sync_int_ext;
		    break;
#else
		case t_uint:
		    emit_sync_uint(acode);
		    cmp_any_any(acode, node->code);
		    load_result(acode);
		    lit_sync = lit_sync_register|
			lit_sync_implicit|lit_sync_int_ext;
		    break;
		case t_uint32:
		    if (!(lit_sync & lit_sync_int_ext))
			new_movi_i(acode, JIT_V2, 0);
		case t_int:
		    if (!(lit_sync & lit_sync_implicit))
			store_ireg_implicit(acode, true);
#endif
		default:
		    cmp_any_any(acode, node->code);
		    load_result(acode);
		    lit_sync = lit_sync_register|
			lit_sync_implicit|lit_sync_int_ext;
		    break;
	    }
	    break;
	default:
	    switch (lit_type) {
		case t_int8:		case t_uint8:
		case t_int16:		case t_uint16:
		case t_int32:		case t_uint32:
		    if (!(lit_sync & lit_sync_int_ext))
			zero_sign_extend(icode, lit_type);
		case t_int:
		    fail = new_label(acode, null);
		    if (!(lit_sync & lit_sync_implicit))
			store_ireg_implicit(acode, true);
		    cmp_any_any(acode, node->code);
		    load_result(acode);
		    load_stack(icode);
		    cmp_any_int(icode, node->code, fail);
		    pop_stack(icode);
		    store_result(icode);
		    done = new_jmpi(icode, null);
		    done = new_label(acode, done);
		    lit_sync = lit_sync_register|
			lit_sync_implicit|lit_sync_int_ext;
		    break;
		case t_uint:
		    /* jump if positive in int64 representation */
#if __WORDSIZE == 32
		    next = new_bgei_i(icode, null, JIT_V2, 0);
		    store_ireg_implicit_rgz(icode, false, JIT_V1, JIT_V2);
#else
		    next = new_bgei_l(icode, null, JIT_V1, 0);
		    store_ireg_implicit_rgz(icode, false, JIT_V1);
#endif
		    /* jump if coerced to mpz */
		    done = new_jmpi(icode, null);
		    /* fallback if cannot compare in jit */
		    fail = new_label(acode, null);
		    if (!(lit_sync & lit_sync_implicit))
			store_ireg_implicit(acode, true);
		    /* coerced to mpz */
		    new_label(acode, done);
		    cmp_any_any(acode, node->code);
		    load_result(acode);
		    /* merge point if positive value */
		    new_label(icode, next);
		    load_stack(icode);
		    cmp_any_int(icode, node->code, fail);
		    pop_stack(icode);
		    store_result(icode);
		    done = new_jmpi(icode, null);
		    done = new_label(acode, done);
		    lit_sync = lit_sync_register|
			lit_sync_implicit|lit_sync_int_ext;
		    break;
		case t_float32:
		    fail = new_label(acode, null);
		    if (!(lit_sync & lit_sync_float_ext))
			new_extr_f_d(acode, JIT_FPR0, JIT_FPR1);
		    if (!(lit_sync & lit_sync_implicit))
			store_freg_implicit(acode, true);
		    cmp_any_any(acode, node->code);
		    load_result(acode);
		    load_stack(fcode);
		    cmp_any_float32(fcode, node->code, fail);
		    pop_stack(fcode);
		    store_result(fcode);
		    done = new_jmpi(fcode, null);
		    new_label(acode, done);
		    lit_sync = lit_sync_register|
			lit_sync_implicit|lit_sync_int_ext;
		    break;
		case t_float:
		    fail = new_label(acode, null);
		    if (!(lit_sync & lit_sync_implicit))
			store_freg_implicit(acode, true);
		    cmp_any_any(acode, node->code);
		    load_result(acode);
		    load_stack(fcode);
		    cmp_any_float(fcode, node->code, fail);
		    pop_stack(fcode);
		    store_result(fcode);
		    done = new_jmpi(fcode, null);
		    new_label(acode, done);
		    lit_sync = lit_sync_register|
			lit_sync_implicit|lit_sync_int_ext;
		    break;
		default:
		    new_ldxi_i(icode, JIT_R0, JIT_V0,
			       offsetof(ethread_t, r0) + offsetof(evalue_t, t));
		    next = new_bnei_i(icode, null, JIT_R0, t_int);
		    new_label(fcode, next);
		    next = new_bnei_i(fcode, null, JIT_R0, t_float);
		    fail = new_label(acode, next);
		    cmp_any_any(acode, node->code);
		    load_result(acode);
		    load_stack(icode);
		    cmp_any_int(icode, node->code, fail);
		    pop_stack(icode);
		    store_result(icode);
		    done = new_jmpi(icode, null);
		    load_stack(fcode);
		    cmp_any_float(fcode, node->code, fail);
		    pop_stack(fcode);
		    store_result(fcode);
		    done = new_label(acode, done);
		    new_jmpi(fcode, done);
		    lit_sync = lit_sync_register|
			lit_sync_implicit|lit_sync_int_ext;
		    break;
	    }
    }
    lit_type = t_uint8;
    return (list);
}
static east_list_t *
emit_cmp(east_list_t *list, east_node_t *node)
{
    list = parse_cmp(list, node);
    parse_flush(-1);
    return (list);
}
#undef store_result
#undef load_result

static void
as_l_i_i(eint32_t code, ecode_t opcode)
{
    new_ldxi_i(code, JIT_R0, JIT_R1,
	       -sizeof(evalue_t) + offsetof(evalue_t, v.i) +
	       offsetof(edata_t, s.l));
#if __WORDSIZE == 32
    if (opcode == eop_add)	new_addr_i(code, JIT_V1, JIT_R0, JIT_V1);
    else			new_subr_i(code, JIT_V1, JIT_R0, JIT_V1);
#else
    if (opcode == eop_add)	new_addr_l(code, JIT_V1, JIT_R0, JIT_V1);
    else			new_subr_l(code, JIT_V1, JIT_R0, JIT_V1);
#endif
}
static void
as_l_l_l(eint32_t code, ecode_t opcode)
{
#if __WORDSIZE == 32
    new_ldxi_i(code, JIT_R0, JIT_R1,
	       -sizeof(evalue_t) + offsetof(evalue_t, v.i) +
	       offsetof(edata_t, s.l));
    new_ldxi_i(code, JIT_R2, JIT_R1,
	       -sizeof(evalue_t) + offsetof(evalue_t, v.i) +
	       offsetof(edata_t, s.h));
    if (opcode == eop_add) {
	new_addcr_ui(code, JIT_V1, JIT_R0, JIT_V1);
	new_addxr_ui(code, JIT_V2, JIT_R2, JIT_V2);
    }
    else {
	new_subcr_ui(code, JIT_V1, JIT_R0, JIT_V1);
	new_subxr_ui(code, JIT_V2, JIT_R2, JIT_V2);
    }
#else
    new_ldxi_l(code, JIT_R0, JIT_R1,
	       -sizeof(evalue_t) + offsetof(evalue_t, v.i));
    if (opcode == eop_add)	new_addr_l(code, JIT_V1, JIT_R0, JIT_V1);
    else			new_subr_l(code, JIT_V1, JIT_R0, JIT_V1);
#endif
}
static void
as_a_l_l(eint32_t code, ecode_t opcode,
	 ebool_t sync, ebool_t type, elit_node_t *fail)
{
#if __WORDSIZE == 32
   /* load low word */
    new_ldxi_i(code, JIT_R2, JIT_R1,
	       -sizeof(evalue_t) + offsetof(evalue_t, v.i) +
	       offsetof(edata_t, s.l));
    if (opcode == eop_add)	new_addr_ui(code, JIT_R0, JIT_R2, JIT_V1);
    else			new_subr_ui(code, JIT_R0, JIT_R2, JIT_V1);
    /* store low word now so that JIT_R0 becames free */
    new_stxi_i(code, offsetof(ethread_t, r0) +
	       offsetof(evalue_t, v.i) + offsetof(edata_t, s.l),
	       JIT_V0, JIT_R0);
    /* compute carry and store it in JIT_R0 */
    if (opcode == eop_add)	new_ltr_ui(code, JIT_R0, JIT_R0, JIT_R2);
    else			new_gtr_ui(code, JIT_R0, JIT_R0, JIT_R2);
    /* copy high word to JIT_R2 because state may be
     * only in registers, and no point in storing it
     * in the thread state twice, so, do not modify
     * JIT_V1 and JIT_V2
     */
    new_movr_i(code, JIT_R2, JIT_V2);
    /* abort if carry causes overflow in high word */
    new_boaddr_i(code, fail, JIT_R2, JIT_R0);
    /* carry information no longer required; load high word */
    new_ldxi_i(code, JIT_R0, JIT_R1,
	       -sizeof(evalue_t) + offsetof(evalue_t, v.i) +
	       offsetof(edata_t, s.h));
    /* compute high word and jump on overflow */
    if (opcode == eop_add)	new_boaddr_i(code, fail, JIT_R0, JIT_R2);
    else			new_bosubr_i(code, fail, JIT_R0, JIT_R2);
    /* no overflow */
    new_stxi_i(code, offsetof(ethread_t, r0) +
	       offsetof(evalue_t, v.i) + offsetof(edata_t, s.h),
	       JIT_V0, JIT_R0);
    if (sync) {
	new_movr_i(code, JIT_V2, JIT_R0);
	/* only need to reload if out of registers */
	new_ldxi_i(code, JIT_V1, JIT_V0,
		   offsetof(ethread_t, r0) + offsetof(evalue_t, v.i) +
		   offsetof(edata_t, s.l));
    }
#else
    new_ldxi_l(code, JIT_R0, JIT_R1,
	       -sizeof(evalue_t) + offsetof(evalue_t, v.i));
    if (opcode == eop_add)	new_boaddr_l(code, fail, JIT_R0, JIT_V1);
    else			new_bosubr_l(code, fail, JIT_R0, JIT_V1);
    new_stxi_l(code, offsetof(ethread_t, r0) + offsetof(evalue_t, v.i),
	       JIT_V0, JIT_R0);
    if (sync)
	new_movr_l(code, JIT_V1, JIT_R0);
#endif
    if (type) {
	new_movi_i(code, JIT_R0, t_int);
	new_stxi_i(code, offsetof(ethread_t, r0) + offsetof(evalue_t, t),
		   JIT_V0, JIT_R0);
    }
}
static void
as_a_l_a(eint32_t code, ecode_t opcode, elit_node_t *fail)
{
#if __WORDSIZE == 64
    elit_node_t		*done;
    elit_node_t		*next;
#endif
    new_ldxi_i(code, JIT_R0, JIT_V0,
	       offsetof(ethread_t, r0) + offsetof(evalue_t, t));
#if __WORDSIZE == 32
    new_bnei_i(code, fail, JIT_R0, t_int);
#else
    next = new_bnei_i(code, null, JIT_R0, t_int);
#endif
    if (!(lit_sync & lit_sync_register))
	load_ireg_implicit(code);
    as_a_l_l(code, opcode, false, true, fail);
#if __WORDSIZE == 64
    done = new_jmpi(code, null);
    new_label(code, next);
    new_bnei_i(code, fail, JIT_R0, t_float);
    if (!(lit_sync & lit_sync_register))
	load_freg_implicit(code);
    as_d_l_d(code, opcode);
    store_freg_implicit(code, true);
    new_label(code, done);
#endif
}
static void
as_a_a_l(eint32_t code, ecode_t opcode, elit_node_t *fail)
{
#if __WORDSIZE == 64
    elit_node_t		*done;
    elit_node_t		*next;
#endif
    new_ldxi_i(code, JIT_R0, JIT_R1,
	       -sizeof(evalue_t) + offsetof(evalue_t, t));
#if __WORDSIZE == 32
    new_bnei_i(code, fail, JIT_R0, t_int);
#else
    next = new_bnei_i(code, null, JIT_R0, t_int);
#endif
    if (!(lit_sync & lit_sync_register))
	load_ireg_implicit(code);
    as_a_l_l(code, opcode, false, true, fail);
#if __WORDSIZE == 64
    done = new_jmpi(code, null);
    new_label(code, next);
    new_bnei_i(code, fail, JIT_R0, t_float);
    if (!(lit_sync & lit_sync_register))
	load_ireg_implicit(code);
    if (!(lit_sync & lit_sync_long_double))
	new_extr_l_d(code, JIT_FPR0, JIT_V1);
    as_d_d_d(code, opcode);
    store_freg_implicit(code, true);
    new_label(code, done);
#endif
}
static void
as_inner_d_d_d(eint32_t code, ecode_t opcode)
{
    if (opcode == eop_add)	new_addr_d(code, JIT_FPR0, JIT_FPR2, JIT_FPR0);
    else			new_subr_d(code, JIT_FPR0, JIT_FPR2, JIT_FPR0);
}
static void
as_d_i_d(eint32_t code, ecode_t opcode)
{
    new_ldxi_i(code, JIT_R0, JIT_R1,
	       -sizeof(evalue_t) + offsetof(evalue_t, v.i) +
	       offsetof(edata_t, s.l));
    new_extr_i_d(code, JIT_FPR2, JIT_R0);
    as_inner_d_d_d(code, opcode);
}
#if __WORDSIZE == 64
static void
as_d_l_d(eint32_t code, ecode_t opcode)
{
    new_ldxi_l(code, JIT_R0, JIT_R1,
	       -sizeof(evalue_t) + offsetof(evalue_t, v.i));
    new_extr_l_d(code, JIT_FPR2, JIT_R0);
    as_inner_d_d_d(code, opcode);
}
#endif
static void
as_d_d_d(eint32_t code, ecode_t opcode)
{
    new_ldxi_d(code, JIT_FPR2, JIT_R1,
	       -sizeof(evalue_t) + offsetof(evalue_t, v.d));
    as_inner_d_d_d(code, opcode);
}
static void
as_a_d_a(eint32_t code, ecode_t opcode, elit_node_t *fail)
{
    new_ldxi_i(code, JIT_R0, JIT_V0,
	       offsetof(ethread_t, r0) + offsetof(evalue_t, t));
    new_bnei_i(code, fail, JIT_R0, t_float);
    as_d_d_d(code, opcode);
    store_freg_implicit(code, true);
}
static void
as_a_a_d(eint32_t code, ecode_t opcode, elit_node_t *fail)
{
#if __WORDSIZE == 64
    elit_node_t		*done;
    elit_node_t		*next;
#endif
    new_ldxi_i(code, JIT_R0, JIT_R1,
	       -sizeof(evalue_t) + offsetof(evalue_t, t));
#if __WORDSIZE == 32
    new_bnei_i(code, fail, JIT_R0, t_float);
    new_ldxi_d(code, JIT_FPR2, JIT_R1,
	       -sizeof(evalue_t) + offsetof(evalue_t, v.d));
#else
    next = new_beqi_i(code, null, JIT_R0, t_float);
    new_bnei_i(code, fail, JIT_R0, t_int);
    new_ldxi_l(code, JIT_R0, JIT_R1,
	       -sizeof(evalue_t) + offsetof(evalue_t, v.i));
    new_extr_l_d(code, JIT_FPR2, JIT_R0);
    done = new_jmpi(code, null);
    new_label(code, next);
    new_ldxi_d(code, JIT_FPR2, JIT_R1,
	       -sizeof(evalue_t) + offsetof(evalue_t, v.d));
    new_label(code, done);
#endif
    if (!(lit_sync & lit_sync_register))
	load_freg_implicit(code);
    as_inner_d_d_d(code, opcode);
    store_freg_implicit(code, true);
}
static void
as_a_a_a(eint32_t code, ecode_t opcode)
{
    if (opcode == eop_add)	new_calli(acode, evm_add);
    else			new_calli(acode, evm_sub);
}
static east_list_t *
parse_addsub(east_list_t *list, east_node_t *node)
{
    elit_node_t		*done;
    elit_node_t		*fail;
    elit_node_t		*next;
    switch (top_type()) {
	case t_int8:			case t_uint8:
	    switch (lit_type) {
		case t_int8:		case t_uint8:
		    lit_type = t_int16;
		l_i_i:
		    load_stack(icode);
		    as_l_i_i(icode, node->code);
		    pop_stack(icode);
		    lit_sync = lit_sync_register;
		    break;
		case t_int16:		case t_uint16:
		    lit_type = t_int32;
		    goto l_i_i;
		case t_int32:		case t_uint32:
		l_l_i:
		    if (!(lit_sync & lit_sync_int_ext))
			zero_sign_extend(icode, lit_type);
		    load_stack(icode);
		    as_l_l_l(icode, node->code);
		    pop_stack(icode);
		    lit_type = t_int;
		    lit_sync = lit_sync_register;
		    break;
		case t_uint:
		a_l_u:
#if __WORDSIZE == 32
		    next = new_blti_i(icode, null, JIT_V2, 0);
		    new_label(acode, next);
		    store_ireg_implicit_rgz(acode, false, JIT_V1, JIT_V2);
#else
		    next = new_blti_l(icode, null, JIT_V1, 0);
		    new_label(acode, next);
		    store_ireg_implicit_rgz(acode, false, JIT_V1);
#endif
		case t_int:
		a_l_l:
		    fail = new_label(acode, null);
		    load_stack(icode);
		    as_a_l_l(icode, node->code, true,
			     !(lit_sync & lit_sync_implicit), fail);
		    pop_stack(icode);
		    done = new_jmpi(icode, null);
		    if (!(lit_sync & lit_sync_implicit))
			store_ireg_implicit(acode, true);
		    as_a_a_a(acode, node->code);
		    new_label(acode, done);
		    lit_type = t_any;
		    lit_sync = lit_sync_implicit;
		    break;
		case t_float32:
		d_i_f:
		    if (!(lit_sync & lit_sync_float_ext))
			float_extend(fcode, lit_type);
		case t_float:
		d_i_d:
		    load_stack(fcode);
		    as_d_i_d(fcode, node->code);
		    pop_stack(fcode);
		    lit_type = t_float;
		    lit_sync = lit_sync_register;
		    break;
		default:
		a_i_a:
		a_l_a:
		    fail = new_label(acode, null);
		    load_stack(icode);
		    as_a_l_a(icode, node->code, fail);
		    pop_stack(icode);
		    done = new_jmpi(icode, null);
		    as_a_a_a(acode, node->code);
		    done = new_label(acode, done);
		    lit_type = t_any;
		    lit_sync = lit_sync_implicit;
		    break;
	    }
	    break;
	case t_int16:			case t_uint16:
	    switch (lit_type) {
		case t_int8:		case t_uint8:
		case t_int16:		case t_uint16:
		    lit_type = t_int32;				goto l_i_i;
		case t_int32:		case t_uint32:		goto l_l_i;
		case t_int:					goto a_l_l;
		case t_uint:					goto a_l_u;
		case t_float32:					goto d_i_f;
		case t_float:					goto d_i_d;
		default:					goto a_i_a;
	    }
	    break;
	case t_int32:
	    switch (lit_type) {
		case t_int8:		case t_uint8:
		case t_int16:		case t_uint16:
		case t_int32:		case t_uint32:		goto l_l_i;
		case t_int:					goto a_l_l;
		case t_uint:					goto a_l_u;
		case t_float32:					goto d_i_f;
		case t_float:					goto d_i_d;
		default:					goto a_i_a;
	    }
	    break;
	case t_uint32:
	    switch (lit_type) {
		case t_int8:		case t_uint8:
		case t_int16:		case t_uint16:
		case t_int32:		case t_uint32:		goto l_l_i;
		case t_int:					goto a_l_l;
		case t_uint:					goto a_l_u;
#if __WORDSIZE == 64
		case t_float32:
		d_l_f:
		    if (!(lit_sync & lit_sync_float_ext))
			float_extend(fcode, lit_type);
		case t_float:
		d_l_d:
		    load_stack(fcode);
		    as_d_l_d(fcode, node->code);
		    pop_stack(fcode);
		    lit_type = t_float;
		    lit_sync = lit_sync_register;
		    break;
#else
		case t_float32:
		d_l_f:
		    if (!(lit_sync & lit_sync_float_ext))
			float_extend(acode, lit_type);
		case t_float:
		d_l_d:
		    if (!(lit_sync & lit_sync_implicit))
			store_freg_implicit(acode, true);
		    as_a_a_a(acode, node->code);
		    lit_type = t_any;
		    lit_sync = lit_sync_implicit;
		    break;
#endif
		default:					goto a_i_a;
	    }
	    break;
	case t_int:
	    switch (lit_type) {
		case t_int8:		case t_uint8:
		case t_int16:		case t_uint16:
		case t_int32:		case t_uint32:
		    if (!(lit_sync & lit_sync_int_ext))
			zero_sign_extend(icode, lit_type);
		case t_int:					goto a_l_l;
		case t_uint:					goto a_l_u;
		case t_float32:					goto d_l_f;
		case t_float:					goto d_l_d;
		default:					goto a_l_a;
	    }
	    break;
	case t_float:
	    switch (lit_type) {
		case t_int8:		case t_uint8:
		case t_int16:		case t_uint16:
		case t_int32:
		    if (!(lit_sync & lit_sync_int_double))
			new_extr_i_d(fcode, JIT_FPR0, JIT_V1);
		    load_stack(fcode);
		    as_d_d_d(fcode, node->code);
		    pop_stack(fcode);
		    lit_type = t_float;
		    lit_sync = lit_sync_register;
		    break;
#if __WORDSIZE == 64
		case t_int:
		    if (!(lit_sync & lit_sync_long_double))
			new_extr_l_d(fcode, JIT_FPR0, JIT_V1);
		    load_stack(fcode);
		    as_d_d_d(fcode, node->code);
		    pop_stack(fcode);
		    lit_type = t_float;
		    lit_sync = lit_sync_register;
		    break;
		case t_uint:
		    next = new_blti_l(fcode, null, JIT_V1, 0);
		    if (!(lit_sync & lit_sync_long_double))
			new_extr_l_d(fcode, JIT_FPR0, JIT_V1);
		    load_stack(fcode);
		    as_d_d_d(fcode, node->code);
		    pop_stack(fcode);
		    store_freg_implicit(fcode, true);
		    done = new_jmpi(fcode, null);
		    new_label(acode, next);
		    store_ireg_implicit_rgz(acode, false, JIT_V1);
		    as_a_a_a(acode, node->code);
		    new_label(acode, done);
		    lit_type = t_any;
		    lit_sync = lit_sync_implicit;
		    break;
#else
		case t_int:
		    if (!(lit_sync & lit_sync_implicit))
			store_ireg_implicit(acode, true);
		    as_a_a_a(acode, node->code);
		    lit_type = t_any;
		    lit_sync = lit_sync_implicit;
		    break;
		case t_uint:
		    emit_sync_uint(acode);
		    as_a_a_a(acode, node->code);
		    lit_type = t_any;
		    lit_sync = lit_sync_implicit;
		    break;
#endif
		case t_float32:
		    if (!(lit_sync & lit_sync_float_ext))
			float_extend(fcode, lit_type);
		case t_float:
		    load_stack(fcode);
		    as_d_d_d(fcode, node->code);
		    pop_stack(fcode);
		    lit_type = t_float;
		    lit_sync = lit_sync_register;
		    break;
		default:
		    fail = new_label(acode, null);
		    load_stack(fcode);
		    as_a_d_a(fcode, node->code, fail);
		    pop_stack(fcode);
		    done = new_jmpi(fcode, null);
		    as_a_a_a(acode, node->code);
		    new_label(acode, done);
		    lit_type = t_any;
		    lit_sync = lit_sync_implicit;
		    break;
	    }
	    break;
	default:
	    switch (lit_type) {
		case t_int8:			case t_uint8:
		case t_int16:			case t_uint16:
		case t_int32:			case t_uint32:
		    if (!(lit_sync & lit_sync_int_ext))
			zero_sign_extend(icode, lit_type);
		case t_int:
		a_a_l:
		    if (!(lit_sync & lit_sync_implicit))
			store_ireg_implicit(icode, true);
		    fail = new_label(acode, null);
		    load_stack(icode);
		    as_a_a_l(icode, node->code, fail);
		    pop_stack(icode);
		    done = new_jmpi(icode, null);
		    as_a_a_a(acode, node->code);
		    done = new_label(acode, done);
		    lit_type = t_any;
		    lit_sync = lit_sync_implicit;
		    break;
		case t_uint:
#if __WORDSIZE == 32
		    next = new_blti_i(icode, null, JIT_V2, 0);
		    new_label(acode, next);
		    store_ireg_implicit_rgz(acode, false, JIT_V1, JIT_V2);
#else
		    next = new_blti_l(icode, null, JIT_V1, 0);
		    new_label(acode, next);
		    store_ireg_implicit_rgz(acode, false, JIT_V1);
#endif
		    goto a_a_l;
		case t_float32:
		    if (!(lit_sync & lit_sync_float_ext))
			float_extend(fcode, lit_type);
		case t_float:
		    if (!(lit_sync & lit_sync_implicit))
			store_freg_implicit(fcode, true);
		    fail = new_label(acode, null);
		    load_stack(fcode);
		    as_a_a_d(fcode, node->code, fail);
		    pop_stack(fcode);
		    done = new_jmpi(fcode, null);
		    as_a_a_a(acode, node->code);
		    new_label(acode, done);
		    lit_type = t_any;
		    lit_sync = lit_sync_implicit;
		    break;
		default:
		    new_ldxi_i(icode, JIT_R0, JIT_V0,
			       offsetof(ethread_t, r0) + offsetof(evalue_t, t));
		    next = new_bnei_i(icode, null, JIT_R0, t_int);
		    new_label(fcode, next);
		    next = new_bnei_i(fcode, null, JIT_R0, t_float);
		    new_label(acode, next);
		    fail = new_label(acode, null);
		    as_a_a_a(acode, node->code);
		    load_stack(icode);
		    as_a_a_l(icode, node->code, fail);
		    pop_stack(icode);
		    done = new_jmpi(icode, null);
		    load_stack(fcode);
		    as_a_a_d(fcode, node->code, fail);
		    pop_stack(fcode);
		    done = new_label(acode, done);
		    new_jmpi(fcode, done);
		    lit_sync = lit_sync_implicit;
		    break;
	    }
	    break;
    }
    return (list);
}
static east_list_t *
emit_addsub(east_list_t *list, east_node_t *node)
{
    list = parse_addsub(list, node);
    parse_flush(-1);
    return (list);
}
#undef pop_stack
#undef load_stack
#endif
